package com.changan.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.Credentials;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.*;
import com.aliyuncs.exceptions.ClientException;
import com.changan.entity.OssEntity;
import com.changan.response.Result;
import com.changan.service.OssService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.Date;
import java.util.UUID;

@Service
public class OssServiceImpl implements OssService {

    @Autowired
    private OssEntity ossEntity;

    private OSS getOssClient() {
        // 低于
        String endpoint = ossEntity.getEndpoint();
        // Bucket所在地域
        String region = ossEntity.getRegion();

        // 从环境变量中获取访问凭证。运行本代码示例之前，请先配置环境变量
        //EnvironmentVariableCredentialsProvider credentialsProvider = null;
        try {
            //credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            DefaultCredentialProvider credentialsProvider =
                    new DefaultCredentialProvider(ossEntity.getAccessKeyId(),ossEntity.getAccessKeySecret());
            // 创建OSSClient实例。
            // 当OSSClient实例不再使用时，调用shutdown方法以释放资源。
            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
            // 显式声明使用 V4 签名算法
            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);

            return OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .credentialsProvider(credentialsProvider)
                    .region(region)
                    .build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void createBucket(String bucketName) throws ClientException {
        if (StringUtils.isEmpty(bucketName)) {
            bucketName = ossEntity.getBucketName();
        }
        OSS ossClient = getOssClient();
        try {
            // 1. 创建存储空间（Bucket）
            ossClient.createBucket(bucketName);
            // 2.设置oss实例的访问权限：公共读
            ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
            System.out.println("1. Bucket " + bucketName + " 创建成功。");
        } catch (OSSException | com.aliyun.oss.ClientException e) {
            throw new RuntimeException(e);
        } finally {
            ossClient.shutdown();
        }
    }

    @Override
    public void deleteBucket(String bucketName) {
        OSS ossClient = getOssClient();
        if (ossClient.doesBucketExist(bucketName)) {
            ossClient.deleteBucket(bucketName);
        }
    }

    @Override
    public String uploadFile(MultipartFile file) {
        String bucketName = ossEntity.getBucketName();
        OSS ossClient = getOssClient();
        if (!ossClient.doesBucketExist(bucketName)) {
            //创建bucket
            ossClient.createBucket(bucketName);
            //设置oss实例的访问权限：公共读
            ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
        }
        //上传地址
        String uploadUrl = null;
        String datePath = null;
        // 获取上传的文件流
        try {
            InputStream inputStream = file.getInputStream();

            datePath = DateUtil.format(new Date(), "yyyy/MM/dd");
            //文件名：uuid.扩展名
            //获取上传文件的全名称
            String original = file.getOriginalFilename();
            //去掉uuid中生成的-
            String fileName = UUID.randomUUID().toString().replaceAll("-", "");
            //截取掉文件获得扩展名
            String fileType = original.substring(original.lastIndexOf("."));
            //uuid+.jpg/.png
            String newName = fileName + fileType;
            // yyyy/MM/dd+/uuid+.jpg/.png
            fileName = datePath + "/" + newName;
            //如果想要实现图片的预览效果,一定要设置一下几个点
            //1.设置文件 ACL为反正不能为私有  要么是公共读,要么是公共读写
            //2.一定要设置文本类型为(image/jpg)
            ObjectMetadata objectMetadata = new ObjectMetadata();
            //设置公共读权限
            objectMetadata.setObjectAcl(CannedAccessControlList.PublicRead);
            //设置类型
            objectMetadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));

            //文件上传至阿里云
            ossClient.putObject(bucketName, fileName, inputStream, objectMetadata);

            //默认十年不过期
            Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);
            //bucket名称  文件名   过期时间
            uploadUrl = ossClient.generatePresignedUrl(bucketName, fileName, expiration).toString();

            //获取url地址
            //uploadUrl = "https://" + bucketName + "." + endPoint + "/" + fileName;
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            // 关闭OSSClient。
            ossClient.shutdown();
        }
        uploadUrl = uploadUrl.replace(ossEntity.getBucketName() + "." + ossEntity.getEndpoint(), "hnzbxy.com");
        return uploadUrl.substring(0, uploadUrl.indexOf("?"));
    }

    @Override
    public void downloadFile(String fileName) {
        String saveDirectory = "D:\\";
        OSS ossClient = getOssClient();
        // 调用ossClient.getObject返回一个OSSObject实例，该实例包含文件内容及文件元信息。
        OSSObject ossObject = ossClient.getObject(ossEntity.getBucketName(), fileName);

        // 确保保存目录存在
        File dir = new File(saveDirectory);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // 构建保存文件的完整路径
        String saveFilePath = saveDirectory + File.separator + new File(fileName).getName();

        // 调用ossObject.getObjectContent获取文件输入流，可读取此输入流获取其内容。
        try (InputStream inputStream = ossObject.getObjectContent();
             FileOutputStream outputStream = new FileOutputStream(saveFilePath);
             BufferedInputStream bufferedInput = new BufferedInputStream(inputStream);
             BufferedOutputStream bufferedOutput = new BufferedOutputStream(outputStream)) {

            byte[] buffer = new byte[1024 * 8];
            int bytesRead;
            // 读取输入流并写入到文件
            while ((bytesRead = bufferedInput.read(buffer)) != -1) {
                bufferedOutput.write(buffer, 0, bytesRead);
            }
            System.out.println("文件已成功下载到: " + saveFilePath);

        } catch (IOException e) {
            throw new RuntimeException("文件下载失败: " + e.getMessage(), e);
        } finally {
            // 关闭OSSClient。
            ossClient.shutdown();
        }
    }

    @Override
    public void deleteFile(String objectName) {
        OSS ossClient = getOssClient();
        ossClient.deleteObject(ossEntity.getBucketName(), objectName);
    }

    @Override
    public Result listFile() {
        OSS ossClient = getOssClient();
        ObjectListing objectListing = ossClient.listObjects(ossEntity.getBucketName());
        for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
            System.out.println(" - " + objectSummary.getKey() + " (大小 = " + objectSummary.getSize() + ")");
        }
        return Result.ok().data("data", objectListing);
    }

    /**
     * Description: 判断OSS服务文件上传时文件的contentType
     *
     * @param FilenameExtension 文件后缀
     * @return String
     */
    public static String getcontentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        return "image/jpg";
    }
}
